using Furion;
using Magic.Core;
using Magic.Core.Entity;
using Magic.Core.Service;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Net;
using System.Net.Http;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;
using Yitter.IdGenerator;

namespace Magic.Web.Core
{
    [AppStartup(9)]
    public class Startup : AppStartup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            //单位是字节（byte） 1kb=1024byte，默认是30M
            long maxRequestBodySize = Convert.ToInt64(App.Configuration["MaxRequestBodySize"]);
            services.Configure<KestrelServerOptions>(options =>
            {
                options.Limits.MaxRequestBodySize = maxRequestBodySize;
            });
            services.Configure<IISServerOptions>(options =>
            {
                options.MaxRequestBodySize = maxRequestBodySize;
            });

            SqlSugarConfigure(services);

            services.AddJwt<JwtHandler>(enableGlobalAuthorize: true);

            services.AddCorsAccessor();

            // 配置远程请求
            services.AddRemoteRequest(option =>
            {
                // 配置天气预报GZIP
                option.AddHttpClient("wthrcdn", c =>
                {
                    c.BaseAddress = new Uri("http://wthrcdn.etouch.cn/");
                }).ConfigurePrimaryHttpMessageHandler(_ =>
                    new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip });
            });

            services.AddConfigurableOptions<CacheOptions>();

            services.AddControllersWithViews()
                    .AddMvcFilter<RequestActionFilter>()
                    .AddInjectWithUnifyResult<XnRestfulResultProvider>()
                    .AddJsonOptions(options =>
                    {
                        //options.JsonSerializerOptions.DefaultBufferSize = 10_0000;//返回较大数据数据序列化时会截断，原因：默认缓冲区大小（以字节为单位）为16384。
                        options.JsonSerializerOptions.Converters.AddDateFormatString("yyyy-MM-dd HH:mm:ss");
                        options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
                        //options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; // 忽略循环引用 仅.NET 6支持
                    });

            services.AddViewEngine();
            services.AddSignalR();
            services.AddRemoteRequest();

            // 设置雪花id的workerId，确保每个实例workerId都应不同
            var workerId = ushort.Parse(App.Configuration["SnowId:WorkerId"] ?? "1");
            YitIdHelper.SetIdGenerator(new IdGeneratorOptions { WorkerId = workerId });

            // 开启自启动定时任务
            App.GetService<ISysTimerService>().StartTimerJob();

            // 注册EventBus服务
            services.AddEventBus(builder =>
            {
                // 注册 Log 日志订阅者
                builder.AddSubscriber<LogEventSubscriber>();
            });
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            // 添加状态码拦截中间件
            app.UseUnifyResultStatusCodes();

            app.UseHttpsRedirection(); // 强制https
            app.UseStaticFiles();

            // Serilog请求日志中间件---必须在 UseStaticFiles 和 UseRouting 之间
            app.UseSerilogRequestLogging();

            app.UseRouting();

            app.UseCorsAccessor();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseInject(string.Empty);

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapHub<ChatHub>("/hubs/chathub");
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }



        private void SqlSugarConfigure(IServiceCollection services)
        {
            #region 配置sqlsuagr
            List<ConnectionConfig> connectConfigList = new List<ConnectionConfig>();
            //数据库序号从0开始,默认数据库为0
            var config= App.GetConfig<ConnectionDb>("ConnectionStrings");
            //默认数据库
            connectConfigList.Add(new ConnectionConfig
            {
                ConnectionString = config.DefaultDbString,
                DbType = (DbType)Convert.ToInt32(Enum.Parse(typeof(DbType), config.DefaultDbType)),
                IsAutoCloseConnection = true,
                ConfigId = config.DefaultDbNumber,
                InitKeyType = InitKeyType.Attribute
            });
            //业务数据库集合
            foreach (var item in config.DbConfigs)
			{
                connectConfigList.Add(new ConnectionConfig
                {
                    ConnectionString = item.DbString,
                    DbType = (DbType)Convert.ToInt32(Enum.Parse(typeof(DbType), item.DbType)),
                    IsAutoCloseConnection = true,
                    ConfigId = item.DbNumber,
                    InitKeyType = InitKeyType.Attribute
                });
            }
            services.AddSqlSugar(connectConfigList.ToArray()
                , db =>
                {
                    db.Aop.OnLogExecuting = (sql, pars) =>
                    {
                        if (sql.StartsWith("SELECT"))
                        {
                            Console.ForegroundColor = ConsoleColor.Green;
                        }
                        if (sql.StartsWith("UPDATE") || sql.StartsWith("INSERT"))
                        {
                            Console.ForegroundColor = ConsoleColor.White;
                        }
                        if (sql.StartsWith("DELETE"))
                        {
                            Console.ForegroundColor = ConsoleColor.Blue;
                        }
                        //App.PrintToMiniProfiler("SqlSugar", "Info", sql + "\r\n" + db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value)));
                        Console.WriteLine(sql + "\r\n\r\n" + SqlProfiler.ParameterFormat(sql, pars));
                        App.PrintToMiniProfiler("SqlSugar", "Info", SqlProfiler.ParameterFormat(sql, pars));
                    };
                    //执行超时时间
                    db.Ado.CommandTimeOut = 30;
                    //配置多租户全局过滤器
                    db.QueryFilter.Add(new TableFilterItem<SysUser>(FilterExpression<SysUser>()));
                    db.QueryFilter.Add(new TableFilterItem<SysOrg>(FilterExpression<SysOrg>()));
                    db.QueryFilter.Add(new TableFilterItem<SysPos>(FilterExpression<SysPos>()));
                    db.QueryFilter.Add(new TableFilterItem<SysRole>(FilterExpression<SysRole>()));
                    db.QueryFilter.Add(new TableFilterItem<OnlineUser>(FilterExpression()));

                    // 配置加删除全局过滤器
                    db.QueryFilter.Add(new TableFilterItem<SysApp>(it => it.IsDeleted == false));
                    db.QueryFilter.Add(new TableFilterItem<SysCodeGen>(it => it.IsDeleted == false));
                    db.QueryFilter.Add(new TableFilterItem<SysCodeGenConfig>(it => it.IsDeleted == false));
                    db.QueryFilter.Add(new TableFilterItem<SysDictData>(it => it.IsDeleted == false));
                    db.QueryFilter.Add(new TableFilterItem<SysDictType>(it => it.IsDeleted == false));
                    db.QueryFilter.Add(new TableFilterItem<SysFile>(it => it.IsDeleted == false));
                    db.QueryFilter.Add(new TableFilterItem<SysMenu>(it => it.IsDeleted == false));
                    db.QueryFilter.Add(new TableFilterItem<SysNotice>(it => it.IsDeleted == false));
                    db.QueryFilter.Add(new TableFilterItem<SysOauthUser>(it => it.IsDeleted == false));
                    db.QueryFilter.Add(new TableFilterItem<SysOrg>(it => it.IsDeleted == false));
                    db.QueryFilter.Add(new TableFilterItem<SysPos>(it => it.IsDeleted == false));
                    db.QueryFilter.Add(new TableFilterItem<SysRole>(it => it.IsDeleted == false));
                    db.QueryFilter.Add(new TableFilterItem<SysTimer>(it => it.IsDeleted == false));
                    db.QueryFilter.Add(new TableFilterItem<SysUser>(it => it.IsDeleted == false));
                    db.QueryFilter.Add(new TableFilterItem<SysTenant>(it => it.IsDeleted == false));
                });
            #endregion
        }

        /// <summary>
        /// 获取当前租户id
        /// </summary>
        /// <returns></returns>
        private object GetTenantId()
        {
            if (App.User == null) return null;
            return App.User.FindFirst(ClaimConst.TENANT_ID)?.Value;
        }

        /// <summary>
        /// 判断是不是超级管理员
        /// </summary>
        /// <returns></returns>
        private bool IsSuperAdmin()
        {
            if (App.User == null) return false;
            return App.User.FindFirst(ClaimConst.CLAINM_SUPERADMIN)?.Value == AdminType.SuperAdmin.GetHashCode().ToString();
        }

        /// <summary>
        /// 非超级管理员默认添加租户过滤
        /// </summary>
        /// <returns></returns>
        private Expression<Func<T, bool>> FilterExpression<T>() where T : DBEntityTenant
        {
            var superAdminViewAllData = Convert.ToBoolean(App.Configuration["SystemSettings:SuperAdminViewAllData"]);
            if (IsSuperAdmin() && superAdminViewAllData) return m => true;
            return m => m.TenantId == long.Parse(GetTenantId().ToString());
        }

        /// <summary>
        /// 非超级管理员默认添加租户过滤
        /// 在线用户比较特殊，数据库表格设计问题
        /// </summary>
        /// <returns></returns>
        private Expression<Func<OnlineUser, bool>> FilterExpression()
        {
            var superAdminViewAllData = Convert.ToBoolean(App.Configuration["SystemSettings:SuperAdminViewAllData"]);
            if (IsSuperAdmin() && superAdminViewAllData) return m => true;
            return m => m.TenantId == long.Parse(GetTenantId().ToString());
        }
    }
}